﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using MethodWorx.CMS.Providers;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MethodWorx.CMS.Workflow;
using Moq;
using MethodWorx.Core.DomainModel;

namespace MethodWorx.CMS.UI.Tests.Workflow
{
    [TestClass]
    public class WorkflowExecutionEngineTests
    {
        private class StepConfig : IWorkflowConfiguration
        {
            public string SomeConfig { get; set; }

            #region IWorkflowConfiguration Members

            public string GetDescriptionSummary()
            {
                return "";
            }

            #endregion
        }

        [TestMethod]
        public void TestSingleStepWorkflow()
        {
            var stepConfig = new StepConfig { SomeConfig = "SomeConfig" };
            var context = this.GetMockWorkflowExecutionContext();
            var components = this.GetMockComponents(context, new StepConfig[] { stepConfig }).ToList();
            var configuration = this.GetMockWorkflowConfiguration(new StepConfig[] { stepConfig });

            var engine = new WorkflowExecutionEngine(
                components, 
                context,
                configuration);

            engine.Execute();

            Mock.Get(components.First()).Verify();
        }

        [TestMethod]
        public void TestMultipleStepWorkflow()
        {
            var stepConfig1 = new StepConfig { SomeConfig = "SomeConfig" };
            var stepConfig2 = new StepConfig { SomeConfig = "SomeConfig" };
            var context = this.GetMockWorkflowExecutionContext();
            var components = this.GetMockComponents(context, new StepConfig[] { stepConfig1, stepConfig2}).ToList();
            var configuration = this.GetMockWorkflowConfiguration(new StepConfig[] { stepConfig1, stepConfig2 });

            var engine = new WorkflowExecutionEngine(
                components,
                context,
                configuration);

            engine.Execute();

            Mock.Get(components.First()).Verify();
        }

        private WorkflowConfiguration GetMockWorkflowConfiguration(IEnumerable<StepConfig> stepConfigs)
        {
            var config = new WorkflowConfiguration();

            config = new WorkflowConfiguration();
            WorkflowConfigurationStep lastStep = null;
            foreach (var stepConfig in stepConfigs)
            {
                var step = new WorkflowConfigurationStep()
                {
                    ComponentId = Guid.Empty,
                    ComponentConfiguration = stepConfig
                };

                if (lastStep == null)
                    config.StartingStep = step;
                else
                {
                    lastStep.Steps = new WorkflowConfigurationStep[] { step };
                }
                lastStep = step;
            }

            return config;
        }

        private class StubCmsDataProvider : ICmsDataProvider
            {

                public void Initialize()
                {
                    throw new NotImplementedException();
                }

                public T GetService<T>()
                {
                    throw new NotImplementedException();
                }

                public void AddService<TInterface, TConcrete>() where TConcrete : TInterface
                {
                    throw new NotImplementedException();
                }

                public IUnitOfWorkFactory GetUnitOfWorkFactory()
                {
                    return new StubUnitOfWorkFactory();
                }

                public IRepositoryRegistry GetRepositoryRegistry()
                {
                    throw new NotImplementedException();
                }
            }

        private IWorkflowExecutionContext GetMockWorkflowExecutionContext()
        {
            var mock = new Mock<IWorkflowExecutionContext>();
            mock.SetupGet(m => m.CmsDataProvider).Returns(new StubCmsDataProvider());            
            return mock.Object;
        }

        private IEnumerable<IWorkflowComponent> GetMockComponents(IWorkflowExecutionContext context, IEnumerable<StepConfig> configs)
        {
            var mock = new Mock<IWorkflowComponent>();
            mock.Setup(m => m.Id).Returns(Guid.Empty);
            foreach (var stepConfig in configs)
            {
                mock.Setup(m => m.Execute(context, stepConfig))
                    .Returns(StepExecutionResult.Ok())
                    .Verifiable();
            }

            yield return mock.Object;

        }
    }
}
